#ifndef HEAP_TIMER_H
#define HEAP_TIMER_H

#include <queue>
#include <unordered_map>
#include <time.h>
#include <algorithm>
#include <arpa/inet.h>
#include <functional>
#include <assert.h>
#include <chrono>
#include "../Log/log.h"

using TimeoutCallBack = std::function<void()>;  // 超时回调
using Clock = std::chrono::high_resolution_clock; 
using MS = std::chrono::milliseconds;
using TimeStamp = Clock::time_point;

/*
    存储每个定时任务的信息，包括ID、超时时间戳（TimeStamp）
    以及超时时执行的回调函数
*/
struct TimerNode {
    int id;
    TimeStamp expires; // 超时时间
    TimeoutCallBack cb;
    bool operator<(const TimerNode& t)
    {
        return expires < t.expires;
    }
};

class HeapTimer {
public:
    HeapTimer() {heap_.reserve(64); }   // 初始时为堆容器预分配64个TimerNode对象大小的空间
    ~HeapTimer() {clear();}

    void adjust(int id, int newExpires);    // 根据ID调整指定任务的新的超时时间

    void add(int id, int timeOut, const TimeoutCallBack& cb);   // 向定时器添加一个新的定时任务

    void doWork(int id);    // 执行指定ID的定时任务并从堆中移除

    void clear();   // 清除所有定时任务

    void tick();    // 检查并执行所有到期的定时任务

    void pop();     // 移除并处理堆顶（最早超时）的任务

    int GetNextTick();  // 获取下一个定时任务的剩余时间（毫秒）

private:
    void del_(size_t i);    // 根据索引从堆中删除指定的时间任务节点

    void siftup_(size_t i); // 上浮操作，用于在堆中插入新节点或调整节点位置

    bool siftdown_(size_t index, size_t n); // 下沉操作，用于将指定索引节点下沉至正确位置以维持堆属性

    void SwapNode_(size_t i, size_t j);     // 交换堆中两个节点的位置

    std::vector<TimerNode> heap_;   // std::vector容器模式的小根堆，存储所有的定时任务节点
    
    std::unordered_map<int, size_t> ref_;   // 用于根据任务ID快速定位其在堆中的索引位置，建立id与index之间的映射
};

#endif